package service

import (
	"fmt"
	"poker21/model"
	"strconv"
)

func OnGameInit() {
	playGame()
}

func playGame() {
	wallet := 1000.00 //默认开局钱包
	bet := 0.0        //下注金额
	MinBet := 5.0     //最小赌注[5的倍数]
	fmt.Printf("wallet:%v , bet: %v , MinBet: %v \n", wallet, bet, MinBet)

	cardNumArr := [2]int{52, 8}                //参数1:一副牌54张,参数2:生成多少副牌
	var d model.Deck                           //实例化牌
	d.Initialize(cardNumArr[0], cardNumArr[1]) //创建牌
	shuffleTimes := 2                          //洗牌次数
	for ii := 0; ii < shuffleTimes; ii++ {
		d.Shuffle() //洗牌几次
	}
	// fmt.Printf("--d--:%v \n", d)

	//下面是一直玩[可以改成玩多少局结束]
	for wallet > MinBet {
		//如果桌面牌少于17张就重新创建新牌
		fmt.Printf("v :%v d.CardsLeft()桌面剩余牌数 \n", d.CardsLeft())
		if d.CardsLeft() < 17 {
			d.Initialize(cardNumArr[0], cardNumArr[1]) //创建牌
			for ii := 0; ii < shuffleTimes; ii++ {
				d.Shuffle() //洗牌几次
			}
		}
		fmt.Printf("你钱包余额 %v 。\n", wallet)
		bet = getBet(&wallet) //钱包扣除赌注
		fmt.Printf("\n你的赌注是: %v \n", bet)

		// d.CardsNameConcat() //♠1...♠13[这个测试用]
		// fmt.Printf("--d--:%v \n", d)

		playerHand, err := d.Draw(2) //开局玩家2张牌
		if err != nil {
			panic(err)
		}
		dealerHand, err := d.Draw(2) //开局庄家2张牌
		if err != nil {
			panic(err)
		}
		fmt.Printf("playerHand:%v \n dealerHand:%v \n", playerHand, dealerHand)

		if isBlackjack(playerHand) || isBlackjack(dealerHand) {
			printPlayerHand(playerHand)        //打印出手牌
			printDealerHand(dealerHand, false) //打印出手牌并隐藏第一张

			if isBlackjack(dealerHand) && isBlackjack(playerHand) {
				fmt.Println("庄和闲都是Blackjack，平局！")
				wallet = wallet + bet
				continue
			}

			if isBlackjack(dealerHand) {
				fmt.Println("庄家Blackjack，这局玩家输了。")
				continue
			}

			if isBlackjack(playerHand) {
				winnings := bet * 2.5 //玩家是Blackjack，加注2.5倍
				fmt.Printf("玩家Blackjack. 赢了 %.2f。\n", winnings)
				wallet = wallet + winnings
				continue
			}
		}

		// 玩家拿牌或停牌。。。
		playerDone := false
		for !playerDone {
			printPlayerHand(playerHand)
			printDealerHand(dealerHand, true)
			action := getPlayerAction() //获取玩家的操作
			if action == "H" {
				drawnCards, err := d.Draw(1) //拿牌
				if err != nil {
					panic(err)
				}
				playerHand = append(playerHand, drawnCards[0]) //重新组合手牌
				// 是否爆了
				if isBust(playerHand) {
					printPlayerHand(playerHand) //打印出玩家手牌
					fmt.Println("Bust")
					playerDone = true
				}
			}
			if action == "S" {
				playerDone = true
			}
		}
		if isBust(playerHand) {
			continue //玩家牌是否爆了
		}

		dealerDone := false //庄拿牌
		for !dealerDone {
			if handTotal(dealerHand) >= 17 {
				dealerDone = true //庄牌点数>+17停牌
				continue
			}
			drawnCards, err := d.Draw(1)
			if err != nil {
				panic(err)
			}
			dealerHand = append(dealerHand, drawnCards[0])
		}
		printDealerHand(dealerHand, false)

		if handTotal(dealerHand) > 21 {
			fmt.Println("庄家爆了！")
			wallet = wallet + (bet * 2) //2倍赌注
			continue
		}

		if handTotal(playerHand) > handTotal(dealerHand) {
			fmt.Println("玩家点数大，玩家赢了！")
			wallet = wallet + (bet * 2)
			continue
		}

		if handTotal(playerHand) == handTotal(dealerHand) {
			fmt.Println("Push[平局].")
			wallet = wallet + bet
			continue
		}

		if handTotal(playerHand) < handTotal(dealerHand) {
			fmt.Println("庄家赢了！")
			continue
		}
		fmt.Println("确定获胜者时出现问题")
	}
	fmt.Println("你没钱了!")
	return
}

/*
getBet从用户处获取金额并从钱包中减去赌注
重试，直到输入有效的赌注。
*/
func getBet(wallet *float64) float64 {
	bet := 0
	valid := false
	for !valid {
		valid = true
		bet = getInteger("你想下注多少（5的倍数递增）？")
		if bet < 5 {
			valid = false
		}
		if float64(bet) > *wallet {
			valid = false
		}
		if bet%5 != 0 {
			valid = false //赌注不是5的倍数
		}
		if !valid {
			fmt.Println("赌注必须是5的倍数")
		}
	}
	*wallet = *wallet - float64(bet)
	return float64(bet)
}

/*
getInteger通过提示从用户获取任意int。
重试，直到输入有效整数。
*/
func getInteger(prompt string) int {
	valid := true
	input := getString(prompt)
	integer, err := strconv.Atoi(input)
	if err != nil {
		valid = false
	}
	for !valid {
		fmt.Println("无法将您的答案转换为整数")
		input = getString(prompt)
		integer, err = strconv.Atoi(input)
		if err == nil {
			valid = true
		}
	}
	return integer
}

// getString通过提示从用户获取任意字符串。
func getString(prompt string) string {
	fmt.Print(prompt)
	var input string
	fmt.Scanln(&input)
	return input
}

/*
判断2张手牌是不是blackjack,是返回true,否则false
*/
func isBlackjack(hand []model.CardsData) bool {
	fmt.Printf("--hand--:%v \n", hand)
	if len(hand) != 2 {
		return false
	}
	//先判断第1张是不是A,再判断第2张是不是10
	if hand[0].Point == 1 {
		if hand[1].Point >= 10 && hand[1].Point <= 13 {
			return true
		}
	}
	//先判断第2张是不是A,再判断第1张是不是10
	if hand[1].Point == 1 {
		if hand[0].Point >= 10 && hand[0].Point <= 13 {
			return true
		}
	}
	return false
}

func printHand(hand []model.CardsData) {
	for _, card := range hand {
		fmt.Printf("%s  ", card.CardsNameOnebyOne())
	}
	fmt.Printf(" 点数Total: %d\n", handTotal(hand))
}

// 打印出玩家手牌
func printPlayerHand(hand []model.CardsData) {
	fmt.Printf("Player 手牌: ")
	printHand(hand)
}

// 打印出庄家手牌
func printDealerHand(hand []model.CardsData, hideFirst bool) {
	fmt.Printf("Dealer 手牌: ")
	if hideFirst {
		fmt.Printf("XX  %s  \n", hand[1].CardsNameOnebyOne())
	} else {
		printHand(hand)
	}
}

// handTotal返回21点手牌数值
func handTotal(hand []model.CardsData) int {
	total := 0        //统计手牌点数
	numberOfAces := 0 //统计A牌的个数
	for _, card := range hand {
		//判断A牌，点数+1
		if card.Point == 1 {
			numberOfAces = numberOfAces + 1
		} else {
			//CardsJQK对J、Q、K 返回true，对所有其他返回false，CardsA对A 返回true，对所有其他返回false
			if card.CardsJQK() || card.CardsA() {
				total = total + 10 //J,Q,K,A是10点
			} else {
				total = total + card.Point //累加点数
			}
		}
	}

	//在多副牌组中，一手牌上可能有多个Ace（超过4个）]
	if numberOfAces > 0 {
		// [好多个A]除最后一个Ace外，其他所有Ace都必须是1，因为11+11=22（爆了）
		for numberOfAces > 1 {
			total = total + 1
			numberOfAces = numberOfAces - 1
		}
		// [仅1个A]如果最后一个Ace是11并没有导致爆，那就把它变成11
		if total+11 > 21 {
			total = total + 1
		} else {
			total = total + 11 // 如果11不会导致爆，那就值是11
		}
	}
	return total
}

// 如果手牌打破/超过21，则返回true
func isBust(hand []model.CardsData) bool {
	if handTotal(hand) > 21 {
		return true
	}
	return false
}

/*
玩家命令行输入h拿牌或s停牌
*/
func getPlayerAction() string {
	validInput := false
	input := ""
	for !validInput {
		input = getString("[H]it or [S]tand? ") //命令行输入
		if input == "hit" || input == "Hit" || input == "H" || input == "h" {
			validInput = true
			input = "H"
		}
		if input == "stand" || input == "Stand" || input == "S" || input == "s" {
			validInput = true
			input = "S"
		}
		if !validInput {
			fmt.Println("[无效选项。h拿牌或s停牌]")
		}
	}
	return input
}
